
#include "imageloader.h"
#include "ui_imageloader.h"

#ifndef QT_NO_CONCURRENT
const int THUMBNAIL_SIZE = 97;        // Size of thumbnail

/*
 *	Concurrently load image from file and return qimage  
 *	scaled to size of thumbnail 
 */
QImage loadImage(const QString &fileName)
{
	// Load image from file
    Mat img = imread(fileName.toStdString());
	// Check if image is valid
    if(!img.data)
    {
        qDebug() << "data null";
        return QImage();
    }
    Mat rgb;
	// Convert img to rgb from bgr
    cvtColor(img, rgb, CV_BGR2RGB);

    QImage image = QImage(rgb.data, rgb.cols, rgb.rows, rgb.step, QImage::Format_RGB888);
    image = image.scaled(THUMBNAIL_SIZE, THUMBNAIL_SIZE, Qt::KeepAspectRatio, Qt::FastTransformation);

    return image;
}

ImageLoader::ImageLoader(QWidget *parent) :
    QDialog(parent),
    m_ui(new Ui::ImageLoader)
{
    m_ui->setupUi(this);
    m_ui->scrollAreaWidgetContents->setLayout(m_ui->horizontalLayout);
    m_ui->scrollArea->setAutoFillBackground(true);

    mapper = new QSignalMapper;
    loader = new QFutureWatcher<QImage>;

    theButton = 0;
    loadedFiles = 0;
	// Register object type transfered in between 
    qRegisterMetaType<QImage>("QImage");
	// Initialize ui
    bar = m_ui->scrollArea->horizontalScrollBar();
    bar->setMinimum(0);
    bar->setSliderPosition(0);
	// Size of each move of scrollbar
    bar->setSingleStep(100);
    bar->setPageStep(300);
	// Progress bar settings
    progress.setFixedWidth(350);
    progress.setLabelText("Loading experimental images...please wait");

    connect(m_ui->leftButton, SIGNAL(released()), this, SLOT(moveLeft()));
    connect(m_ui->leftButton, SIGNAL(pressed()), this, SLOT(slideLeft()));
    connect(m_ui->rightButton, SIGNAL(released()), this, SLOT(moveRight()));
    connect(m_ui->rightButton, SIGNAL(pressed()), this, SLOT(slideRight()));
    connect(mapper, SIGNAL(mapped(int)), this, SLOT(displayImage(int)));
    connect(loader, SIGNAL(resultReadyAt(int)), this, SLOT(addButton(int)));
    connect(loader, SIGNAL(finished()), this, SLOT(finished()));
    connect(loader, SIGNAL(progressRangeChanged(int,int)), &progress, SLOT(setRange(int,int)));
    connect(loader, SIGNAL(progressValueChanged(int)), &progress, SLOT(setValue(int)));
    connect(&progress, SIGNAL(canceled()), loader, SLOT(cancel()));
}

ImageLoader::~ImageLoader()
{
    if(theButton) delete theButton;
	// Clear list for storing 
    buttonList.clear();
	// Stop futuer watcher
    loader->cancel();
    loader->waitForFinished();

    delete m_ui;
    delete loader;
    loader = 0;
}

void ImageLoader::changeEvent(QEvent *e)
{
    QDialog::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

/*
 *	Reload image loader based on current image files and map each icon with 
 *	corresponding image file. 
 *
 */
void ImageLoader::reload()
{
	// Count of current image files
    int count = files.size();
    if(count == 0)
    {
        return;
    }
    // Clear button list
    buttonList.clear();
	// Wait for previous future watcher to finish
    if(loader->isRunning())
    {
        loader->cancel();
        loader->waitForFinished();
    }
	// For each index associated with a file, create a button and 
	// append to the end of button list
    for(int i = 0; i < count; i++)
    {
        QToolButton *click = new QToolButton;
        buttonList.append(click);
    }
	// set mapping for each image file and have futurewatcher
	// to check status of each image.
    loader->setFuture(QtConcurrent::mapped(files, loadImage));
    progress.exec();
}

/*
 *	This method is called everytime an image icon is clicked/mapped. Then
 *	get id of mapped image file and display it on the left side of image 
 *	loader. 
 *
 */
void ImageLoader::displayImage(int id)
{
	// Mapped image file
    QString fileName = files.at(id);
	// Load mapped image file
    Mat temp = imread(fileName.toStdString());
	// Check image data whether valid
    if(!temp.data) return;

    Mat rgb;
	// Convert to RGB format
    cvtColor(temp, rgb, CV_BGR2RGB);
	// Get QImage from raw data
    QImage qTemp = QImage(rgb.data, rgb.cols, rgb.rows, rgb.step, QImage::Format_RGB888);
    if(qTemp.isNull()) return;
    else qTemp = qTemp.scaled(m_ui->imageLabel->size(), Qt::IgnoreAspectRatio);

    m_ui->imageLabel->setPixmap(QPixmap::fromImage(qTemp, 0));
	// Highlight clicked button
    if(theButton) theButton->setStyleSheet("");
    theButton = buttonList[id];
    theButton->setStyleSheet("background-color: #dd9619;"
                          "border-width: 3px;");
    currFile = fileName;
	// emit signal that an image file is selected
    emit imageSelected(fileName);
}

/*
 *	Add a vector of image files
 */
void ImageLoader::addFiles(const QVector<QString>& files)
{
    this->files = files;
}

/*
 *	Update thumbnails/icons in scrollbar based on input filter
 */
void ImageLoader::updateIcons(const QStringList& filter)
{
	// Loop through each of current image file
    for(int i = 0; i < files.size(); i++)
    {
        const QString file = files.at(i);
        bool contain = false;
		// Loop through each element of filter 
        for(int j = 0; j < filter.size(); j++)
        {
			// Current filter element
            QString fil = filter.at(j);
			// If current file contains any part of, then current
			// file needs to be kept
            if(file.contains(fil))
            {
                contain = true;
            }
        }
		// After each iteration of the filter, if flag 'contain' 
		// is still false, then file at index 'i' needs to be 
		// filtered out and mapping associated with the file needs
		// to removed as well
        if(!contain)
        {
            files.remove(i);
            mapper->removeMappings(buttonList[i]);
            buttonList.removeAt(i);
        }
    }
}

/*
 *	Once an image has been loaded, then create a tool button
 *	associated with just loaded image
 */
void ImageLoader::addButton(int id)
{
    QIcon icon;
	// Get Qimage just loaded
    QImage image = loader->resultAt(id);
    if(!image.isNull())
    {

		// Get associated button from button list
        QToolButton *click = buttonList.at(id);
        icon.addPixmap(QPixmap::fromImage(image, 0));
		// Add icon onto the button
        click->setIconSize(icon.actualSize(QSize(THUMBNAIL_SIZE, THUMBNAIL_SIZE)));
        click->setIcon(icon);
		// Add button to the UI
        m_ui->horizontalLayout->addWidget(click);
		// Connect event listen for click event
        connect(click, SIGNAL(clicked()), mapper, SLOT(map()));
		// Set mapping for button with an id
        mapper->setMapping(click, id);

        loadedFiles++;
    }
    else
    {
        qDebug() << "null image data";
    }
}

void ImageLoader::finished()
{
    progress.hide();
}

void ImageLoader::moveLeft()
{
    bar->triggerAction(QAbstractSlider::SliderPageStepSub);
}

void ImageLoader::slideLeft()
{
    bar->triggerAction(QAbstractSlider::SliderMove);
}

void ImageLoader::moveRight()
{
    bar->triggerAction(QAbstractSlider::SliderPageStepAdd);
}

void ImageLoader::slideRight()
{
    bar->triggerAction(QAbstractSlider::SliderMove);
}

/*
 *  Display result image on the right side of image loader
 */
void ImageLoader::addResultImg(const Mat &img)
{
    if(!img.data) return;

    QImage qTemp;

    Mat rgb;
    cvtColor(img, rgb, CV_BGR2RGB);
    // Get a copy of result image
    resultImg = img.clone();

    uchar *data = rgb.data;
    int width = rgb.cols;
    int height = rgb.rows;
    int bytes = rgb.step;
    int chn = rgb.channels();

    if(chn == 1)
        qTemp = QImage(data, width, height, bytes, QImage::Format_Mono);
    else
        qTemp = QImage(data, width, height, bytes, QImage::Format_RGB888);

    if(qTemp.isNull()) return;
    else qTemp = qTemp.scaled(m_ui->imageLabel->size(), Qt::KeepAspectRatio);

    m_ui->imageLabel_2->setPixmap(QPixmap::fromImage(qTemp, 0));
}

/*
 *  Clear imageloader's result image
 */
void ImageLoader::clearDisplay()
{
    m_ui->imageLabel_2->setPixmap(QPixmap());
}

QString ImageLoader::getFileByIndex(int id)
{
    if(files.size() == 0)
        return "";
    return files.at(id);
}

QString ImageLoader::getCurrFile()
{
    if(currFile.length() == 0)
        return "";

    return currFile;
}

int ImageLoader::getCurrIndex()
{
    if(currFile.length() == 0)
        return -1;

    return files.indexOf(currFile);
}

#endif // QT_NO_CONCURRENT
